# !/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2023/4/25 20:48
# @Author : xyjiang1216
# @Email : jiangxuyan@nudt.edu.cn
# @File : itp_utils.py
# @Version: OpenPlanner2.0
import math
from typing import List

from OpenPlanner.core.src.op_class import OPClass
from OpenPlanner.examples.itp_demo.itp_algo_input import ITPLink, ITPStream
from OpenPlanner.examples.itp_demo.itp_tabu import schedSet, schedInfo, globalResource, cqfResource
from OpenPlanner.util.compute_hyper_period import compute_hyper_period


def _itp_init_planning_graph(link_array, stream_array, instance_array, slot):
    # 2. 初始化ITPStream
    for stream_obj in stream_array:
        stream_obj.period_in_slot = math.ceil(stream_obj.period / slot)
        stream_obj.latency_req_in_slot = math.ceil(stream_obj.latency_requirement / slot)


def _itp_init_sched_set(stream_array: List[ITPStream]):
    tsn_sched_set = schedSet()
    tsn_sched_set.cur_flow_num = len(stream_array)
    for i in range(tsn_sched_set.cur_flow_num):
        flow_id = stream_array[i].stream_id
        sched_info = schedInfo(flow_id=flow_id)
        tsn_sched_set.sched.append(sched_info)
    return tsn_sched_set


def _itp_init_global_queue_resource(link_array: List[ITPLink],
                                    stream_array,
                                    slot):
    g_resource = globalResource()

    hyper_period = compute_hyper_period(*[stream_obj.period for stream_obj in stream_array])
    total_slot_num_in_hyper_period = math.ceil(hyper_period / slot)

    g_resource.cur_total_sched_slot_num = total_slot_num_in_hyper_period

    for link in link_array:
        link_resource = []
        queue_size = link.queue_size
        for s in range(total_slot_num_in_hyper_period):
            cqf = cqfResource()
            cqf.total_len = queue_size
            cqf.free_len = queue_size
            link_resource.append(cqf)

        g_resource.cqf_resource.append(link_resource)

    return g_resource


def itp_reinit_instance_hook(op_obj: OPClass,
                             **kwargs):
    # 2. 初始化ITPStream
    slot = kwargs['slot']
    stream_array = op_obj.algo_input.stream_array
    for stream_obj in stream_array:
        stream_obj.period_in_slot = math.ceil(stream_obj.period / slot)
        stream_obj.latency_req_in_slot = math.ceil(stream_obj.latency_requirement / slot)
